import glm
import OpenGL.GL as gl
import numpy as np
import pygl
from common import Sphere

class SolidLighting:
    def __init__(self, positions:np.ndarray, normals:np.ndarray, 
                 indices:np.ndarray) -> None:
        gl.glEnable(gl.GL_DEPTH_TEST)
        self.num_vertices = len(positions)
        self.number_indices = len(indices)
        self.program = pygl.ProgramVF("intermediate/shaders/phong.vs", 
                                      "intermediate/shaders/phong.fs")
        self.normal_vbo = pygl.VertexBufferObject(normals)
        self.position_vbo = pygl.VertexBufferObject(positions)
        self.vao = pygl.VertexArrayObject()
        self.ebo = pygl.ElementBufferObject(indices)
        self.vao.setElementBuffer(self.ebo)
        binding_point_position = 0
        binding_point_normal = 1
        self.vao.setVertexBuffer(self.position_vbo, binding_point_position, 0, 
                                 3 * gl.sizeof(gl.GLfloat))
        self.vao.setVertexBuffer(self.normal_vbo, binding_point_normal, 0, 
                                 3 * gl.sizeof(gl.GLfloat))
        attribute_position = pygl.VertexAttribute("position", 0, 3, 
                                                  gl.GL_FLOAT, False, 0)
        attribute_normal = pygl.VertexAttribute("normal", 1, 3, 
                                                  gl.GL_FLOAT, False, 0)
        self.vao.setVertexAttribute(binding_point_position, attribute_position)
        self.vao.setVertexAttribute(binding_point_normal, attribute_normal)
        self.rotation = glm.vec3(0.0, 0.0, 0.0)
        self.position = glm.vec3(0.0, 0.0, 0.0)
        self.scale = glm.vec3(1.0, 1.0, 1.0)
        self.updateModelMatrix()
        self.surface_color =  glm.vec3(146.0/255.0, 150.0/255.0, 242.0/255.0)
        self.ambient_color = glm.vec3(1.0, 1.0, 1.0)
        self.Ka = 0.4
        self.Kd = 0.9
        self.Ks = 1.0
        self.shininess = 60.0
        self.show_light = True
        self.light_program = pygl.ProgramVF("intermediate/shaders/geometry.vs", 
                                      "intermediate/shaders/geometry.fs")
        self.light = Sphere(0.2)
        self.light_color = glm.vec3(1.0, 1.0, 1.0)
        self.light.position = glm.vec3(1.0, 3.0, 0.0)

    def render(self, view_matrix: glm.mat4, projection_matrix: glm.mat4, 
               camera_position:glm.vec3) -> None:
        self.program.use()
        self.program.setUniformMatrix4fv(0, self.model_matrix)
        self.program.setUniformMatrix4fv(1, view_matrix)
        self.program.setUniformMatrix4fv(2, projection_matrix)
        self.program.setUniform3fv(3, self.surface_color)
        self.program.setUniform3fv(4, self.light_color)
        self.program.setUniform3fv(5, self.light.position)
        self.program.setUniform3fv(6, self.ambient_color)
        self.program.setUniform3fv(7, camera_position)
        self.program.setUniform1f(8, self.Ka)
        self.program.setUniform1f(9, self.Kd)
        self.program.setUniform1f(10, self.Ks)
        self.program.setUniform1f(11, self.shininess)
        self.program.setUniform1i(12, 4)
        self.vao.bind()
        gl.glDrawElements(gl.GL_TRIANGLES, self.number_indices, 
                          gl.GL_UNSIGNED_INT, None)

        # 代表灯位置的球体
        if self.show_light:
            self.light_program.use()
            self.light.updateModelMatrix()
            self.light_program.setUniformMatrix4fv(0, self.light.model_matrix)
            self.light_program.setUniformMatrix4fv(1, view_matrix)
            self.light_program.setUniformMatrix4fv(2, projection_matrix)
            self.light_program.setUniform1i(3, 1)
            self.light_program.setUniform3fv(4, self.light_color)
            self.light.render()

    def delete(self)->None:
        self.vao.delete()
        self.ebo.delete()
        self.position_vbo.delete()
        self.normal_vbo.delete()
        self.program.delete()
        self.light_program.delete()
        self.light.delete()

    def updateModelMatrix(self)->None:
        scale_matrix = glm.scale(glm.mat4(1.0), self.scale)
        rotation_matrix = glm.rotate(glm.mat4(1.0), glm.radians(self.rotation.x), 
                                     glm.vec3(1.0, 0.0, 0.0))
        rotation_matrix = glm.rotate(rotation_matrix, 
                        glm.radians(self.rotation.y), glm.vec3(0.0, 1.0, 0.0))
        rotation_matrix = glm.rotate(rotation_matrix, 
                        glm.radians(self.rotation.z), glm.vec3(0.0, 0.0, 1.0))
        translation_matrix = glm.translate(glm.mat4(1.0), self.position)
        self.model_matrix = translation_matrix * rotation_matrix * scale_matrix